-
Notifications
You must be signed in to change notification settings - Fork 16
[신동진] Sprint9 #132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 신동진
Are you sure you want to change the base?
[신동진] Sprint9 #132
Conversation
|
|
||
| // Method Security 활성화 | ||
| @EnableMethodSecurity | ||
| @Configuration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'EnableWebSecurity' 어노테이션이 누락되신듯합니다.
| level: | ||
| com.sprint.mission.discodeit: debug | ||
| org.hibernate.SQL: debug | ||
| org.hibernate.orm.jdbc.bind: trace No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
org.springframework.security 에 대한 로깅 레벨 적용이 필요해 보입니다.
| private final BinaryContentRepository binaryContentRepository; | ||
| private final BinaryContentStorage binaryContentStorage; | ||
|
|
||
| PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
서비스에서 이렇게 생성해서 구현하는 것은 잘못된 방법입니다.
SecurityConfig 에서 빈 생성 메서드를 추가하시기 바랍니다.
| private final UserRepository userRepository; | ||
|
|
||
| @Override | ||
| public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Transactional(readOnly = true) 를 추가해주시면 좋을것 같아요
|
|
||
| @GetMapping("/me") | ||
| public ResponseEntity<UserDto> getUserMe(@AuthenticationPrincipal DiscodeitUserDetails userDetails) { | ||
| return ResponseEntity.ok(userDetails.getUserDto()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getUserDto 로 가져와서 사용하면 세션이 생성될때의 정보가 있어서, 최신정보와 차이가 있을 수 있습니다.
검증만하고 조회할때는 최신정보를 제공하기위해 서비스 에서 조회하는메서드를 호출해주시기 바랍니다.
|
|
||
| @Override | ||
| public Collection<? extends GrantedAuthority> getAuthorities() { | ||
| return List.of(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기서 빈리스트를 조회해오는 로직이 보이는데, userDto 의 role 정보에 맞는 권한 리스트를 만들어주는 작업이 필요한것 같습니다.
|
|
||
| @Slf4j | ||
| @RestControllerAdvice | ||
| public class GlobalExceptionHandler { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AuthorizationDeniedException 에 대한 핸들링도 커스텀하게 처리해주시기 바랍니다.
| @JsonManagedReference | ||
| @Setter(AccessLevel.PROTECTED) | ||
| @OneToOne(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) | ||
| private UserStatus status; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
세션 정보가 들어옴에 따라 제거가 필요해 보입니다.
|
심화내용에 대한 구현이 미흡해 보입니다. 추가학습을 통해 구현해보시면 더 좋을것 같습니다. |
요구사항
기본
Spring Security 환경설정
프로젝트에 Spring Security 의존성을 추가하세요.
Security 설정 클래스를 생성하세요.
SecurityFilterChain Bean을 선언하세요.
개발 환경에서 Spring Security 모듈의 로깅 레벨을 trace로 설정하세요.
CSRF 보호 설정하기
디스코드잇은 CSR 방식이기 때문에 CSRF 토큰은 다음과 같이 처리합니다.
CsrfTokenRepository 구현체를 CookieCsrfTokenRepository로 설정하세요.
CsrfTokenRequestHandler 컴포넌트를 대체하세요.
CSRF 토큰을 발급하는 API를 구현하세요.
회원가입
인증 - 로그인
각 컴포넌트의 기본 구현체가 무엇인지 디버깅해보세요.
로그인을 처리할 url을 /api/auth/login로 설정하세요.
UserDetailsService 컴포넌트를 대체하세요.
UserDetails 컴포넌트를 대체하세요.
AuthenticationSuccessHandler 컴포넌트를 대체하세요.
AuthenticiationFailureHandler 컴포넌트를 대체하세요.
이제 로그인 처리는 SecurityFilterChain에서 모두 처리되기 때문에 기존에 구현했던 로그인 관련 코드는 제거하세요.
인증 - 세션을 활용한 현재 사용자 정보 조회
이전 버전까지의 디스코드잇 프론트엔드에서는 현재 사용자 정보를 브라우저의 세션 스토리지(user-storage)에서 관리해왔습니다.
브라우저의 세션 스토리지는 Javascript로 접근이 가능하기 때문에, XSS(Cross-Site Scripting) 공격에 취약합니다.
따라서 프론트엔드 2.0.x 부터는 사용자 정보를 브라우저의 메모리에서 관리하도록 변경되었습니다.
하지만, 메모리에 저장된 정보는 브라우저 새로고침 시 모두 삭제됩니다.
따라서 새로고침 시 쿠키에 저장된 세션 ID를 통해 현재 사용자 정보를 조회합니다.
인증 - 로그아웃
Spring Security의 logout 흐름은 그대로 유지하면서 필요한 부분만 대체합니다.
이번 미션에서는 2가지 요소를 대체합니다.
로그아웃을 처리할 url을 /api/auth/logout로 설정하세요.
LogoutSuccessHandler 컴포넌트를 대체하세요.
인가 - 권한 정의
다음과 같이 권한을 정의하세요.
데이터베이스 스키마를 변경하세요.
회원 가입 시 모든 사용자는 USER 권한을 기본 권한으로 설정하세요.
사용자 권한을 수정하는 API를 구현하세요.
애플리케이션 실행 시 ADMIN 권한을 가진 어드민 계정이 초기화되도록 구현하세요.
DiscodietUserDetails.getAuthorities를 수정하세요.
인가 - 권한 적용
authorizeHttpRequests를 활성화하고, 모든 요청을 인증하도록 설정하세요.
다음의 요청은 인증하지 않도록 설정하세요.
Method Security를 활성화하세요.
Service의 메소드 별로 아래의 조건에 맞게 권한을 수정하세요.
적절한 권한이 없는 경우 403 응답을 반환하세요.
RoleHierarchy를 활용해 권한의 계층 구조를 정의하세요.
심화
세션 관리 고도화
동일한 계정으로 동시 로그인할 수 없도록 설정하세요.
권한이 변경된 사용자가 로그인 상태라면 세션을 무효화하세요.
UserStatus 엔티티 대신 SessionRegistry를 활용해 사용자의 로그인 여부를 판단하도록 리팩토링하세요.
로그인 고도화 - RememberMe
권한 적용 고도화
주요 변경사항
스크린샷
멘토에게